perm filename GRNSAI.SAI[S,HE]5 blob sn#666562 filedate 1982-07-03 generic text, type C, neo UTF8
COMMENT ⊗   VALID 00012 PAGES
C REC  PAGE   DESCRIPTION
C00001 00001
C00003 00002	These routines are for outputting gray-level pictures on the Grinnell.
C00007 00003	INTERNAL PROCEDURE SNOOZE(INTEGER TIME(0))
C00010 00004	INTERNAL PROCEDURE BUFOUT
C00014 00005	INTERNAL PROCEDURE GRNINI
C00025 00006	INTERNAL SIMPLE PROCEDURE EXE11BUF(INTEGER ADDR, BUFLEN)
C00031 00007	INTERNAL PROCEDURE TSTGRN(INTEGER TESTNO)
C00033 00008	INTERNAL PROCEDURE MAPGRN(INTEGER CARD,TABL,NBITS)
C00034 00009	INTERNAL PROCEDURE ERASEG(INTEGER CHAN,BITS('7777))
C00035 00010	INTERNAL PROCEDURE VIDGRN(INTEGER LEFT, TOP, CHAN INTEGER ARRAY PIC
C00040 00011	! routines to input a picture from the grnnell
C00048 00012	END "GRNSAI"
C00049 ENDMK
C⊗;
Comment These routines are for outputting gray-level pictures on the Grinnell.
  They are a temporary hack to "hold the dike" until the device-independent
  graphics library can be completed and should be regarded as such. AAM '80;
Comment Hah!  Such youthful optimism.  AAM '82;

ENTRY VIDGRN,TSTGRN,MAPGRN,GRNINI,GRNFIN,GRNINS,BUFOUT, SNOOZE, GRNIN, GWORDIN,
	INPIC, EXE11BUF, QUICKGIN, QUICKBUF;
BEGIN "GRNSAI"

Comment misc. definitions;
REQUIRE "{}<>" DELIMITERS;

REQUIRE "GRNFHD.SAI[HDR,HE]" SOURCE_FILE;
REQUIRE "PIXHDR.SAI[HDR,HE]" SOURCE_FILE;
REQUIRE "GRNDEF[HDR,HE]" SOURCE_FILE;
REQUIRE "ELFHDR.SAI[HDR,HE]" SOURCE_FILE;
REQUIRE "CRDHDR.SAI[HDR,HE]" SOURCE_FILE;
DEFINE TRACE={FALSE};	COMMENT Print out debugging marks;
DEFINE SEEINSTR={FALSE}; COMMENT Look at Grinnell instructions in octal before executring them;
DEFINE HANGNOISY={TRUE}; COMMENT Complain loudly when DR11 hangs;
DEFINE HANGWAIT={FALSE}; COMMENT Allow user to examine signals before resetting
				PDP11 when DR11 hangs;
DEFINE HANGRETRY={FALSE}; COMMENT When DR11 hangs, keep retrying until it doesn't;
DEFINE SPEEDCHECK={FALSE}; COMMENT Special timing hacks;
DEFINE GRNDEV={TRUE};	COMMENT Grinnell a device yet?;
DEFINE BUSTCHK={FALSE};  COMMENT Check BUSTED.GRN for latest status?;

DEFINE ! = {COMMENT};
DEFINE CRLF = { ('15&'12) };

DEFINE GRNBUF(BUFFER,BUFLEN,BITS) = {
	Comment Cause DR-11B to do its thing;
IF NOT BUSTED THEN
 BEGIN
	WAITFOR11;
	IFC TRACE THENC print("!"); ENDC
	ELFBKO(START11MEM,(BUFLEN),BUFFER,(BITS)); Comment move the buffer to the 11;
	ELFOUT(DRWC,-(BUFLEN));	Comment NOTE: word count not byte count;
	ELFOUT(DRBA,(START11MEM LAND '177777) LSH 1); comment MAKE INTO BYTE ADR;
	ELFOUT(DRST,DRWRITE);	     comment Grinnell needs at least one clock;
	ELFOUT(DRST,GO LOR DRWRITE LOR XBA);     comment cycle between setting of;
						 comment write and go;
 END;
}; ! end of GRNBUF;

Comment global variables;
BOOLEAN DEMO;			COMMENT Whether a demo file is being created;
INTEGER DEMOCHAN;		COMMENT The channel the file is open on;
INTEGER DEMOSAVE;		COMMENT Word used to pack instructions;
BOOLEAN EVENWORD;
INTEGER DEMBREAK,DEMEOF;	COMMENT For demo file stuff;
BOOLEAN BUSTED;			Comment Whether or not Grinnell is in normal mode;
INTEGER NXTLOC;			Comment next PDP11 address to load;
SAFE Comment to speed up GRNINS;
INTEGER ARRAY INSBUF[1:LEN11MEM]; Comment 10-buffer for 11 memory.;
INTEGER LOKCHAN;	Comment channel used for opening file which locks grinnell;
INTERNAL PROCEDURE SNOOZE(INTEGER TIME(0));
Comment SNOOZE is the delay that is used for waiting for the DR11-B;
Comment sleeps for 1/60 of a second (until next tick, I guess);
Comment unless argument is nonzero, then it sleeps that many seconds;

BEGIN "SNOOZE"
   QUICK_CODE "SLEEP"
      MOVE '13,TIME;
      CALLI '13,'31
   END "SLEEP";
IFC TRACE THENC   Print(":");  ENDC
END "SNOOZE";  Comment what a kludge;

INTERNAL PROCEDURE WAITFOR11;
BEGIN "WAITFOR11"
INTEGER SLEEPY;
    Comment wait until the DR11B is ready and the arm is not moving;
	SLEEPY ← 0;
	WHILE ¬(ELFIN(DRST) LAND READY) DO 
	    BEGIN SNOOZE; SLEEPY ← SLEEPY+1;
IFC TRACE THENC
!		  IF SLEEPY > 20 THEN ;
		    PRINT("DRST: ",CVOS(ELFIN(DRST)),'15&'12);
ENDC
	    COMMENT Added code to check for hanging not due to Grinnell;
	    IF SLEEPY > 120 COMMENT Allow 2 sec for this one;
		THEN BEGIN "HUNG BUT NOT OUR FAULT"
		STRING RESET;
		PRINT("The PDP-11 appears to be hung.  Shall I try a RESET?");
		PRINT('15&'12&"Don't say yes unless you are prepared to deal with");
		PRINT('15&'12&"an angry arm hacker (check first):  ");
		RESET←INCHWL;
		IF (RESET="Y") OR (RESET="y") THEN POWERFAIL ELSE
		    BEGIN "HARLYNS HACK"
			COMMENT This works sometimes;
			PRINT("Trying recovery by zeroing wordcount."&'15&'12);
			ELFOUT(DRWC,0);
			ELFOUT(DRST,0);
		    END "HARLYNS HACK";
		SLEEPY←0;
		END "HUNG BUT NOT OUR FAULT";
	    END;
END "WAITFOR11";

INTERNAL PROCEDURE BUFOUT;
Comment BUFOUT outputs any pending Grinnell commands from the 10 memory to the
	Grinnell.;

BEGIN "BUFOUT"
INTEGER BUFLEN,SLEEPY;		Comment number of words to output, No. of sleep cycles;

   BUFLEN ← NXTLOC - 1;  Comment because NXTLOC points to the NEXT location.;
   IF BUFLEN > 0 THEN 
      BEGIN
	GRNBUF(INSBUF,BUFLEN,0);
	NXTLOC ← 1		     comment restart word count;
      END
END "BUFOUT";

INTERNAL INTEGER PROCEDURE GWORDIN;
  BEGIN "GWORDIN"
  Comment This procedure causes the 11 to read a word from the 
	  Grinnell interface and then returns this value. It should be uesd after
	  a read back instruction is given;
IF NOT BUSTED THEN
 BEGIN
    BUFOUT;		
    Comment wait until the DR11B is ready and the arm is not moving;
    WAITFOR11;
    ELFOUT(DRWC, -1); 	                          Comment Readback count 16 bit wds;
    ELFOUT(DRBA,(START11MEM LAND '177776) LSH 1); comment MAKE INTO BYTE ADR;
    ELFOUT(DRST, DRREAD);
    ELFOUT(DRST, GO LOR DRREAD LOR XBA);
    WAITFOR11;
  RETURN(ELFIN(START11MEM))
 END
END "GWORDIN"; 		  Comment input data from 11;

INTERNAL PROCEDURE GRNINI;
Comment GRNINI sets up the Grinnell buffer(set of instructions in PDP11 memory).
	It should be called before GRNINS is ever called.;

BEGIN "GRNINI"
   REQUIRE "APPEND[TST,AAM]" LOAD_MODULE;
   EXTERNAL INTEGER PROCEDURE APPEND(INTEGER CHAN; REFERENCE INTEGER COUNT);
   INTEGER COUNT,BRCHAR,EOF,FAILURE,BUSTCHAN,ACCTCHAN,SAVEW,SAVED;
   STRING MINUTES;
   BOOLEAN NEWFILE;
   INTEGER DATE,DAY,MONTH,TICKS,MIN,HR;
   ELFINI;
   DEMO ← FALSE; COMMENT No demos unless specifically requested;
   NXTLOC ← 1;	Comment set up place to put instructions in buffer;
   EOF ← -1;
IFC GRNDEV THENC
   DO OPEN(LOKCHAN ← GETCHAN,"GRN", 0, 0,0,1,BRCHAR,EOF) UNTIL EOF = 0;
  ELSEC
   OPEN(LOKCHAN ← GETCHAN,"DSK", '17, 0,0,1,BRCHAR,EOF);
   ENTER(LOKCHAN,"GRNLOK.TBL[TMP,AAM]",FAILURE);
   IF FAILURE LAND 3 THEN BEGIN		 comment if file is being used then wait;
	   PRINT("Waiting for Grinnell....");
	   WHILE FAILURE LAND 3 DO BEGIN
		SNOOZE;
		ENTER(LOKCHAN,"GRNLOK.TBL[TMP,AAM]",FAILURE);
           END;
	   PRINT("Gotcha!"&'15&'12);
   END;
  ENDC
  IFC BUSTCHK THENC
   BUSTCHAN←GETCHAN;
   OPEN(BUSTCHAN,"DSK",0,0,0,1,BRCHAR,EOF);
   LOOKUP(BUSTCHAN,"BUSTED.GRN[TMP,AAM]",FAILURE);
   BUSTED ← FAILURE = 0;
   RELEASE(BUSTCHAN);
   IF BUSTED THEN PRINT("Grinnell is busted.  No graphics will be done.",CRLF);
  ENDC
   ACCTCHAN←GETCHAN;
   OPEN(ACCTCHAN,"DSK",0,1,1,COUNT,BRCHAR,EOF);
   LOOKUP(ACCTCHAN,"GRINEL.SUX[DOC,HE]",NEWFILE);
   ENTER(ACCTCHAN,"GRINEL.SUX[DOC,HE]",EOF);
   IF NOT NEWFILE THEN APPEND(ACCTCHAN,COUNT);
   COMMENT Fix the spazz where the caller has done a SETFORMAT;
   GETFORMAT(SAVEW,SAVED); SETFORMAT(0,0);
   OUT(ACCTCHAN,CVXSTR(CALL(0,"GETPPN"))&'11); comment PPN;
   OUT(ACCTCHAN,CVXSTR(CALL(0,"GETNAM"))&'11); comment jobname;
   DATE ← CALL(0,"DATE");   DAY←(DATE MOD 31)+1;  MONTH←((DATE DIV 31) MOD 12)+1;
   OUT(ACCTCHAN,CVS(MONTH)&"/"&CVS(DAY)&'11);
   TICKS ← CALL(0,"TIMER");  MIN←(TICKS DIV 3600)MOD 60; HR←TICKS DIV 216000;
   COMMENT Make life easier for accounting programs;
   MINUTES←CVS(MIN); IF LENGTH(MINUTES)<2 THEN MINUTES←"0"&MINUTES;
   OUT(ACCTCHAN,CVS(HR)&":"&MINUTES&'15&'12);
   SETFORMAT(SAVEW,SAVED);
   RELEASE(ACCTCHAN);
END "GRNINI";

INTERNAL SIMPLE PROCEDURE DEMOMODE(STRING DEVICE,FILENAME);
COMMENT Set up demonstration mode.  Call after calling GRNINI;

BEGIN "DEMOMODE"

DEMO ← TRUE;
EVENWORD ← FALSE;
DEMOCHAN ← GETCHAN;
OPEN(DEMOCHAN,DEVICE,'10,0,19,1,DEMBREAK,DEMEOF);
ENTER(DEMOCHAN,FILENAME,DEMEOF);

END "DEMOMODE";

INTERNAL PROCEDURE DEMOFIN;
COMMENT	Finish off the demo file, if one exists.;

BEGIN "DEMOFIN"
   IF DEMO THEN
	BEGIN
	    COMMENT If not an even number of words, stick in a no-op at the end;
	    IF EVENWORD THEN WORDOUT(DEMOCHAN,(DEMOSAVE LSH 18) LOR NOP);
	    RELEASE(DEMOCHAN);
	    DEMO ← FALSE;
	END;
END "DEMOFIN";

INTERNAL PROCEDURE GRNFIN;
Comment GRNFIN flushes the current Grinnell buffer and releases the ELF.;

BEGIN "GRNFIN"
   BUFOUT;
   DEMOFIN;
   RELEASE(LOKCHAN);	Comment release file which locks grinnell;
   ELFREL
END "GRNFIN";

PROCEDURE DEMOWORD(INTEGER WORD);
BEGIN
IF EVENWORD THEN
    WORDOUT(DEMOCHAN,(DEMOSAVE LSH 18) LOR WORD)
ELSE
    DEMOSAVE ← WORD;
EVENWORD ← NOT EVENWORD
END;

INTERNAL SIMPLE PROCEDURE GRNINS(INTEGER WORD);
Comment GRNINS puts one Grinnell instruction into the PDP-11 buffer;

BEGIN "GRNINS"
Comment   ELFOUT(NXTLOC,WORD); Comment this was MUCH too slow!;
   IFC SEEINSTR THENC
   PRINT(CVOS(WORD),CRLF);
   ENDC
   IF DEMO THEN DEMOWORD(WORD);
   INSBUF[NXTLOC] ← WORD;
   NXTLOC ← NXTLOC + 1;
   IF NXTLOC > LEN11MEM THEN BUFOUT
END "GRNINS";

INTERNAL PROCEDURE GRNIN(INTEGER ADDR, COUNT, READBACKMODE(0), USETBITS(0));
  BEGIN "GRNIN"
  INTEGER SLEEPY,CT;
  IFC HANGRETRY THENC
  BOOLEAN HUNG; COMMENT Tells whether the DR11 is well hung;
  ENDC
  Comment This procedure causes the 11 to read count words from the 
	  Grinnell interface and then returns this value. It should be used after
	  a SPD instruction with at least the readback bit set;
    IFC HANGRETRY THENC
    DO BEGIN "TRY TO READ BUFFER"
    HUNG ← FALSE;
    ENDC
    GRNINS(RPD LOR READBACKMODE);
    BUFOUT;		
 IF NOT BUSTED THEN
  BEGIN "READ IN A BLOCK FROM GRINNELL"
    WAITFOR11;
    ELFOUT(DRWC, -COUNT);                         Comment Readback count 16 bit wds;
    ELFOUT(DRBA,(START11MEM LAND '177777) LSH 1); comment MAKE INTO BYTE ADR;
ifc trace thenc
print("type <cr> to initiate read (set GO bit):");inchwl;
endc
    ELFOUT(DRST, DRREAD);
    ELFOUT(DRST, GO LOR DRREAD LOR XBA);

Comment Now we need to wait for the DR-11 to get finished.  We used to call SNOOZE
	but it always waits 1/60th sec min, which was too slow.  We have experi-
	mentally determined that COUNT*4 is not enough and COUNT*5 is the minimum
	that works.;
    CT ← COUNT*5;
    QUICK_CODE
	LABEL LOOP;
	MOVE  '13,CT;
LOOP:	SOJG  '13,LOOP;
    END;

ifc trace thenc print("x"); endc
	SLEEPY ← 0;
	WHILE ¬(ELFIN(DRST) LAND READY) DO 
	    BEGIN SNOOZE; SLEEPY←SLEEPY+1;
IFC TRACE THENC
!		  IF SLEEPY > 20 THEN ;
		    PRINT("DRST: ",CVOS(ELFIN(DRST)),'15&'12);
ENDC
comment Code has been added to detect a hung DR11B...AAM 11/4/80;
		IF SLEEPY > 30  COMMENT If DR11 doesn't respond in .5 sec;
		THEN BEGIN "HUNG DR11"
		INTEGER I,WC;
		IFC HANGNOISY THENC
	       Comment extend the sign of a 16-bit word (bug fixed 12/19/80 AAM);
		WC←ELFIN(DRWC) LOR '777777600000;
		PRINT("DR11 status register (octal) = ",CVOS(ELFIN(DRST)),CRLF);
		PRINT(CRLF,"The DR-11B hung thinking it had to read ",
		 -WC," (decimal) more words.  The words it read are:",
		 " (octal)",CRLF);
		ELFBKI(START11MEM,COUNT+WC,ADDR,0);
		FOR I←0 STEP 1 UNTIL COUNT+WC-1 DO
		    PRINT(CVOS(MEMORY[ADDR+I]),CRLF);
		ENDC
		IFC HANGWAIT THENC
		PRINT("Type <cr> to do a power fail reset: ");INCHWL;
		ENDC
		IFC HANGRETRY THENC
		HUNG ← TRUE;
		ENDC
		POWERFAIL;
		END "HUNG DR11"
	    END;
    IFC SPEEDCHECK THENC PRINT("I slept ",SLEEPY," times.",CRLF); ENDC
    IFC HANGRETRY THENC
    END "TRY TO READ BUFFER" UNTIL NOT HUNG;
    ENDC
    Comment check to see if words are packed when reading from the elf;
    IF (USETBITS LAND TWOWRDSL) THEN COUNT ← COUNT/2 + (COUNT MOD 2);
    ELFBKI(START11MEM,COUNT, ADDR,USETBITS);	  Comment input data from 11;
  END "READ IN A BLOCK FROM GRINNELL";
  END "GRNIN";        
INTERNAL SIMPLE PROCEDURE EXE11BUF(INTEGER ADDR, BUFLEN);
  Comment this procedure is for fast execution of grinnell commands that are 
  	  repeated often.  It starts the DR11B using the ADDR and WORDCOUNT;
  BEGIN "EXE11BUF"
	IF NOT BUSTED THEN BEGIN
	    WHILE ¬(ELFIN(DRST) LAND READY) DO ;
	    ELFOUT(DRWC,-BUFLEN);   Comment NOTE: word count not byte count;
	    ELFOUT(DRBA,(ADDR LAND '177777) LSH 1); comment MAKE INTO BYTE ADR;
	    ELFOUT(DRST,DRWRITE);        comment Grinnell needs at least one clock;
					 comment cycle between setting of;
	    ELFOUT(DRST,GO LOR DRWRITE LOR ((ADDR LAND '300000) LSH -11));     
				 comment write and go with extended bus addr bits;
	END;
   
  END "EXE11BUF";

INTERNAL SIMPLE PROCEDURE QUICKBUF;
  Comment this procedure is for fast execution of grinnell commands that are 
  	  repeated often.  It starts the DR11B using the ADDR and WORDCOUNT;
  BEGIN "QUICKBUF"
   OWN INTEGER BUFLEN;
   BUFLEN ← NXTLOC - 1;
   IF BUFLEN > 0 THEN 
      BEGIN
	NXTLOC ← 1;		     comment restart word count;
	IF NOT BUSTED THEN BEGIN
	    WHILE ¬(ELFIN(DRST) LAND READY) DO ;
	    ELFBKO(START11MEM,(BUFLEN),INSBUF,0); Comment move the buffer to the 11;
	    ELFOUT(DRWC,-BUFLEN);   Comment NOTE: word count not byte count;
	    ELFOUT(DRBA,(START11MEM LAND '177777) LSH 1); comment MAKE INTO BYTE ADR;
	    ELFOUT(DRST,DRWRITE);        comment Grinnell needs at least one clock;
					 comment cycle between setting of;
	    ELFOUT(DRST,GO LOR DRWRITE LOR ((START11MEM LAND '300000) LSH -11));  
				 comment write and go with extended bus addr bits;
	END;
   
    END;
  END "QUICKBUF";

INTERNAL SIMPLE PROCEDURE QUICKGIN(INTEGER ADDR, COUNT, READBACKMODE(0), USETBITS(0));
  Comment this procedure is for fast input of data from the Grinnell to the  
          11.  It starts the DR11B using the ADDR and WORDCOUNT
	  Since it does not wait (i.e. no snooze) it is  suitable for space war 
	  mode;
 Comment An RPD instruction must be given prior to the call of this procedure;
  BEGIN "QUICKGIN"
    INTEGER CT;
    IF NOT BUSTED THEN BEGIN
	GRNINS(RPD LOR READBACKMODE);
!	PRINT("waiting before loop 1 ", COUNT, crlf);
	QUICKBUF;
	for ct ← 1 step 1 until COUNT*5 do;
!	    CT ← COUNT*5;
!	    QUICK_CODE
!		LABEL LOOP1;
!		MOVE  '13,CT;
!	LOOP1:  SOJG  '13,LOOP1;
!	    END;
!	PRINT("waiting at loop 1",crlf);
	WHILE ¬(ELFIN(DRST) LAND READY) DO ;  Comment Yes, this is the wait loop;
	ELFOUT(DRWC,-COUNT);	Comment NOTE: word count not byte count;
	ELFOUT(DRBA,(START11MEM LAND '177777) LSH 1); comment MAKE INTO BYTE ADR;
	ELFOUT(DRST,DRREAD);	     comment Grinnell needs at least one clock;
				     comment cycle between setting of;
	ELFOUT(DRST,GO LOR DRREAD LOR ((START11MEM LAND '300000) LSH -11));     
				 comment write and go with extended bus addr bits;
!	CT ← COUNT*5;
!	QUICK_CODE
!	    LABEL LOOP2;
!	    MOVE  '13,CT;
!   LOOP2:  SOJG  '13,LOOP2;
!	END;
!	PRINT("waiting before loop 2 ", COUNT, crlf);
	for ct ← 1 step 1 until COUNT*5 do;
!	PRINT("waiting at loop 2",crlf);
	WHILE ¬(ELFIN(DRST) LAND READY) DO ;  comment don't leave until done;
	Comment check to see if words are packed when reading from the elf;
	IF (USETBITS LAND TWOWRDSL) THEN COUNT ← COUNT/2 + (COUNT MOD 2);
	ELFBKI(START11MEM,COUNT, ADDR,USETBITS);      Comment input data from 11;
    END
   
  END "QUICKGIN";
INTERNAL PROCEDURE TSTGRN(INTEGER TESTNO);
Comment GRNTST runs the internal diagnostic test on the Grinnell.  These are
	designed to be run with TESTNO = 0, then 1, then 2 then 3, but this is
	not mandatory.;
BEGIN "GRNTST"
   GRNINS(SPD LOR TEST);
   GRNINS(LPA LOR (TESTNO MOD 4));
   BUFOUT;
END "GRNTST";
INTERNAL PROCEDURE MAPGRN(INTEGER CARD,TABL,NBITS);
Comment MAPGRN sets the video lookup table at CARD, TABL to show the least
	significant NBITS bits.;
BEGIN "MAPGRN"
    INTEGER ARRAY TMAP[0:255];
    INTEGER I, BITMASK, LSHIFT;
    BITMASK ← 2↑NBITS - 1; Comment mask with low NBITS on;
    LSHIFT ← 8 - NBITS;    Comment how far to shift the low NBITS;
    FOR I ← 0 STEP 1 UNTIL 255 DO TMAP[I] ← (I LAND BITMASK) LSH LSHIFT;
    IFVCMAP(CARD, TABL, TMAP);
    BUFOUT;
END "MAPGRN";
INTERNAL PROCEDURE ERASEG(INTEGER CHAN,BITS('7777));
Comment Erase the indicated bits in the indicated channel;
BEGIN "ERASEG"
   GRNINS(LDC LOR (1 LSH CHAN));
   GRNINS(LSM LOR BITS);
   GRNINS(LWM LOR 0); Comment dark background;
   GRNINS(ERS);
   BUFOUT;
END "ERASEG";
INTERNAL PROCEDURE VIDGRN(INTEGER LEFT, TOP, CHAN; INTEGER ARRAY PIC;
				INTEGER SHIFTBY(0));
Comment VIDGRN outputs a gray-scale picture to the Grinnell.
	LEFT - left margin of picture in pixels
	TOP - top margin of picture in pixels
	CHAN - channel of output;
BEGIN "VIDGRN"
INTEGER I;
INTEGER LINE,PIXEL;		Comment Line number being output;
INTEGER UNPACK;			Comment Address of unpacking "subroutine";
INTEGER ARRAY LINBUF[0:PIC[LNBY]]; Comment Buffer sent to 11;

   GRNINS(LDC LOR (1 LSH CHAN));	Comment Select channel;
   GRNINS(LSM LOR '377);	Comment enable all subchannels;
   GRNINS(LWM LOR BITZ);	Comment Set write mode;
ifc TRACE thenc
print("Here we go on channel ",chan);
endc
   GRNINS(LUM LOR E1);		Comment Ea ← Ea+Eb mode;
   GRNINS(LEB LOR 1);		Comment Eb ← 1;
   GRNINS(LLB LOR NEG1);	Comment Lb ← -1;
   GRNINS(LLA LOR TOP);		Comment La ← top margin;
   GRNINS(LEC LOR LEFT);	Comment Ec ← left margin;
   GRNINS(LEA LOR LEFT);	Comment Set Ea to starting value;
Comment Flush anything that might be left over in the PDP11 buffer;
BUFOUT;

Comment Now that all control registers are set up, output all the lines of data.;

Comment I'm trying a new hack here, so for now I'm going to do things unpacked;

Comment assemble up instructions for unpacking one line into LINBUF;
Comment runtime assembler courtesy of PB;
BEGIN "RUNTIME ASSEMBLY"
REQUIRE "ASSEMB.SAI[UTL,PB]" SOURCE_FILE;
CBLK$_BEGIN(1);
L$(UNPACK);
FOR PIXEL ← 0 STEP 1 UNTIL PIC[LNBY]-1 DO
    BEGIN "UNPACK AND STORE ONE PIXEL"
C$	ILDB(2,1);
IF SHIFTBY≠0 THEN C$ LSH(2,hr(SHIFTBY)); Comment HHB this crocko'shit doesnt work if
		SHIFTBY<0 ... generates SHIFTBY !!!! changed to HR(Y) 25-5;
C$	MOVEM(2,LOC(LINBUF[0])+PIXEL);
    END "UNPACK AND STORE ONE PIXEL";
C$	POPJ('17,0);
CBLK$_END(1);
END "RUNTIME ASSEMBLY";

Comment put SLU instruction at end of buffer;
LINBUF[PIC[LNBY]]←(SLU LOR L1 LOR E0); Comment Return to left margin and next line
				(this is La ← La+Lb  and  Ea ← Ec);

IF PIC[LNBY]+1 > LEN11MEM THEN PRINT("Oh no!!!!!!!  HELP!!!!!!!");

Comment Put the ELF in "risky but fast" mode (special system hack);
RISKON;

Comment For each line;
FOR LINE ← 0 STEP 1 UNTIL PIC[PCLN]-1 DO
    BEGIN
	INTEGER BYTPTR;

	Comment Set up byte pointer to the line in AC1, then unpack the
		line into LINBUF;
	BYTPTR←MEMORY[PIC[BPTAB]-1]+PIC[LINTAB+LINE];
	START_CODE
	    MOVE 1,BYTPTR;
	    PUSHJ '17,@UNPACK;
	END;

	Comment Transfer the instructions to the PDP-11...;
	GRNBUF(LINBUF,PIC[LNBY]+1,0);
	IF DEMO THEN
	    FOR I ← 0 STEP 1 UNTIL PIC[LNBY] DO DEMOWORD(LINBUF[I]);
    END;

Comment Take the ELF out of its funny mode;
RISKOFF;

END "VIDGRN";

! routines to input a picture from the grnnell;
PROCEDURE PACKBYTES(INTEGER BYTE1PTR, BYTE2PTR,DESTPTR, NBYTES);
  BEGIN "PACKBYTES"
     LABEL LOOP;
     START_CODE
	MOVE    3,BYTE1PTR;
	MOVE	4,BYTE2PTR;
	MOVE	5,DESTPTR;
	MOVE 	1,NBYTES;
	ash	1,-1;
  LOOP: LDB	2,3;
	IDPB	2,5;
	AOS	3;
	LDB	2,4;
	IDPB	2,5;
	AOS	4;
	SOJG	1,LOOP;
    END;
 END "PACKBYTES";
	
  
INTERNAL PROCEDURE InLine(REFERENCE INTEGER  Ptr; INTEGER linelen);
  BEGIN "InLine"
   INTEGER element;
   INTEGER ARRAY LineIn[1:Linelen/2];  


 ! Now get one scan line from the Grinnell and store it in the 11`s buffer;
 ! and input line from the 11`s memory through the ELF;
 ! The data is read in in packed mode from the Grinnell and then two words per;
 ! word left justified from the 11;
   GRNIN(LOCATION(LINEIN[1]), Linelen/2, BYTEPACK,TWOWRDSL);
 
   FOR element ← 0 STEP 1 UNTIL linelen/4 -1 DO
	MEMORY[ptr + element] ← lineIn[element +1];

 END "InLine";

INTERNAL PROCEDURE INPIC(INTEGER CHAN; INTEGER ARRAY PIC);

 BEGIN "InPic"
   INTEGER line, ptr;
   DEFINE HEIGHT = 512,
	  WIDTH  = 512,
	  BITS   = 8;

 ! Make blank picture with dimensions HxWxB;
   MAKPIX(HEIGHT,WIDTH,BITS,PIC[0]); 


   GRNINI;			! Set up Grinnell buffers;

   GRNINS(LDC LOR (1 LSH CHAN));	! Select channel;
   GRNINS(SPD LOR READBACK);	! Set read mode;
   GRNINS(LUM LOR E1);		! Ea ← Ea+Eb mode;
   GRNINS(LEB LOR 1);		! Eb ← 1;
   GRNINS(LLB LOR NEG1);	! Lb ← -1;
   GRNINS(LLA LOR HEIGHT-1);	! La ← top margin;
   GRNINS(LEC LOR 0);		! Ec ← left margin;
   GRNINS(LEA LOR 0);		! Set Ea to starting value;

 ! Send these commands off to the Grinnell;
   BUFOUT;

 ! Input first line of picture form Grinnell;
   PTR ← MEMORY[PIC[BPTAB]-1,INTEGER] + PIC[LINTAB]; Comment get byte ptr;
   InLine(Ptr, width);

 ! Now get the rest;
   FOR line ← 2 step 1 until Height DO
     BEGIN
       GRNINS(SLU LOR L1 LOR E0);
       BUFOUT;
       PTR ← MEMORY[PIC[BPTAB]-1,INTEGER]+PIC[LINTAB+LINE-1]; Comment get byte ptr;
       IfC trace THENC
         print(line," ");
       ENDC
       InLine(Ptr, width);
     END;

 ! Finished so relaese ELF;
   GRNFIN;

 END "InPic";


INTERNAL PROCEDURE UINPIC(INTEGER CHAN; INTEGER ARRAY PIC);

 BEGIN "UInPic"
   INTEGER line, ptr;
   INTEGER ARRAY LINEIN[1:256];
   DEFINE HEIGHT = 512,
	  WIDTH  = 512,
	  BITS   = 8;

 ! Make blank picture with dimensions HxWxB;
   MAKPIX(HEIGHT,WIDTH,BITS,PIC[0]); 


   GRNINI;			! Set up Grinnell buffers;

   GRNINS(LDC LOR (1 LSH CHAN));	! Select channel;
   GRNINS(LSM LOR '377);	! Enable read back of all 8 bits;
   GRNINS(LEA LOR 0);		! Set Ea to starting value;
   GRNINS(LEB LOR 1);		! Eb ← 1;
   GRNINS(LLA LOR HEIGHT-1);	! La ← top margin;
   GRNINS(LLB LOR '777);	! Lb ← -1;
   GRNINS(LEC LOR 0);		! Ec ← left margin;
   GRNINS(LUM LOR E1);		! Ea ← Ea+Eb mode;
   GRNINS(SPD LOR READBACK);	! Set read mode;

 ! Send these commands off to the Grinnell;
   BUFOUT;

 ! Input first line of picture form Grinnell;
   PTR ← MEMORY[PIC[BPTAB]-1,INTEGER] + PIC[LINTAB]; Comment get byte ptr;
   GRNIN(LOCATION(LINEIN[1]), WIDTH,0,TWOWRDSL);
   PACKBYTES(POINT(BITS,LINEIN[1],15),POINT(BITS,LINEIN[1],31),PTR,WIDTH);

 ! Now get the rest;
   FOR line ← 2 step 1 until Height DO
     BEGIN
       GRNINS(SLU LOR L1 LOR E0);	
       PTR ← MEMORY[PIC[BPTAB]-1,INTEGER]+PIC[LINTAB+LINE-1]; Comment get byte ptr;
       IFC TRACE THENC
	   print(line," ");
       ENDC
       GRNIN(LOCATION(LINEIN[1]), WIDTH,0,TWOWRDSL);
       PACKBYTES(POINT(BITS,LINEIN[1],15),POINT(BITS,LINEIN[1],31),PTR,WIDTH);
	comment shit, changed to 31 after several days of crappy input;
     END;

 ! Finished so release ELF;
   GRNFIN;

 END "UInPic";
END "GRNSAI";